package com.catazy.mvvmlib.ext

import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.blankj.utilcode.util.LogUtils
import com.catazy.mvvmlib.base.activity.BaseVmActivity
import com.catazy.mvvmlib.base.fragment.BaseVmFragment
import com.catazy.mvvmlib.base.viewmodel.BaseViewModel
import com.catazy.mvvmlib.net.BaseResponse
import com.catazy.mvvmlib.net.ResultState
import com.catazy.mvvmlib.net.http.error.ApiException
import com.catazy.mvvmlib.net.parseException
import com.catazy.mvvmlib.net.parseResult
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

/**
 * 作者: Tao
 * 日期: 2024/1/29
 * 时间: 16:15
 * 描述:
 */

/**
 * Activity显示页面状态
 * @param resultState 接口返回值
 * @param onLoading 加载中
 * @param onSuccess 成功回调
 * @param onError 失败回调
 *
 */
fun <T> BaseVmActivity<*>.parseState(
    resultState: ResultState<T>,
    onSuccess: (T) -> Unit,
    onError: ((ApiException) -> Unit)? = null,
    onLoading: (() -> Unit)? = null
) {
    when (resultState) {
        is ResultState.Loading -> {
            showLoading(resultState.loadingMessage)
            onLoading?.run { this }
        }

        is ResultState.Success -> {
            dismissLoading()
            onSuccess(resultState.data)
        }

        is ResultState.Error -> {
            dismissLoading()
            onError?.run { this(resultState.error) }
        }
    }
}

/**
 * Fragment显示页面状态，这里有个技巧，成功回调在第一个，其后两个带默认值的回调可省
 * @param resultState 接口返回值
 * @param onLoading 加载中
 * @param onSuccess 成功回调
 * @param onError 失败回调
 *
 */
fun <T> BaseVmFragment<*>.parseState(
    resultState: ResultState<T>,
    onSuccess: (T) -> Unit,
    onError: ((ApiException) -> Unit)? = null,
    onLoading: ((message: String) -> Unit)? = null
) {
    when (resultState) {
        is ResultState.Loading -> {
            if (onLoading == null) {
                showLoading(resultState.loadingMessage)
            } else {
                onLoading.invoke(resultState.loadingMessage)
            }
        }

        is ResultState.Success -> {
            dismissLoading()
            onSuccess(resultState.data)
        }

        is ResultState.Error -> {
            dismissLoading()
            onError?.run { this(resultState.error) }
        }
    }
}

/**
 * 异步请求，调用协程
 * @param block 耗时操作任务
 * @param success 请求成功回调
 * @param error 请求失败回调
 */
fun <T> BaseViewModel.launch(
    block: () -> T,
    success: (T) -> Unit,
    error: (Throwable) -> Unit = {},
) {
    viewModelScope.launch {
        runCatching {
            withContext(Dispatchers.IO) {
                block()
            }
        }.onSuccess {
            success(it)
        }.onFailure {
            error(it)
        }
    }
}

/**
 * 网络请求 不校验请求结果
 * 比如一些无返回结果或返回结果为空的请求
 * @param block 请求体方法
 * @param resultState 请求回调的数据
 * @param isShowDialog 是否显示加载框
 * @param loadingMessage 加载框显示的内容
 */
fun <T> BaseViewModel.request(
    block: suspend () -> BaseResponse<T>,
    resultState: MutableLiveData<ResultState<T>>,
    isShowDialog: Boolean = false,
    loadingMessage: String = "请求网络中..."
): Job {
    return viewModelScope.launch {
        runCatching {
            if (isShowDialog) resultState.value = ResultState.onAppLoading(loadingMessage)
            block()
        }.onSuccess {
            resultState.parseResult(it)
        }.onFailure {
            LogUtils.e(it.message!!)
            it.printStackTrace()
            resultState.parseException(it)
        }
    }
}

fun <T> BaseViewModel.request(
    block: suspend () -> BaseResponse<T>,
    success: (T) -> Unit,
    resultState: MutableLiveData<ResultState<T>>,
    isShowDialog: Boolean = false,
    loadingMessage: String = "请求网络中..."
): Job {
    return viewModelScope.launch {
        runCatching {
            if (isShowDialog) loadingChange.showDialog.postValue(loadingMessage)
            block()
        }.onSuccess {
            if (isShowDialog) loadingChange.dismissDialog.postValue(false)
            runCatching {
                executeResponse(it) { t -> success(t) }
            }.onFailure { e ->
                e.message?.let { message ->
                    LogUtils.e(message)
                }
                e.printStackTrace()
                resultState.parseException(e)
            }
            resultState.parseResult(it)
        }.onFailure {
            if (isShowDialog) loadingChange.dismissDialog.postValue(false)
            it.message?.let { message ->
                LogUtils.e(message)
            }
            it.printStackTrace()
            resultState.parseException(it)
        }
    }
}

/**
 * 请求结果过滤
 */
suspend fun <T> executeResponse(
    response: BaseResponse<T>,
    success: suspend CoroutineScope.(T) -> Unit
) {
    coroutineScope {
        if (response.isSuccess()) success(response.getResponseData())
        else throw ApiException(response.getResponseCode(), response.getResponseMsg())
    }
}
